CloudFormation で BlockDeviceMapping プロパティを利用している EBS のサイズ拡張を行う方法を教えてください

CloudFormation で BlockDeviceMapping プロパティを利用している EBS のサイズ拡張を行う方法を教えてください

Clock Icon2024.11.25

困っていること

CloudFormation テンプレートの BlockDeviceMappings プロパティを利用して EC2 のルートボリュームに紐づく EBS の設定を実施しています。ディスク拡張を実施するために VolumeSize の値を変更してテンプレートをデプロイしたところ、当該 EC2 のインスタンス再作成が発生してしまいました。
EC2 のインスタンス再作成を伴わずに CloudFormation でボリュームサイズの拡張を行うにはどうすれば良いでしょうか?

どう対応すればいいの?

2024/11/25 現在の仕様として、BlockDeviceMappings プロパティの VolumeSize の値を変更した場合、紐づいている EC2 インスタンスの再作成は避けられません。
以下の CloudFormation のロードマップにおいても関連する issue が open になっていることが確認できます。
https://github.com/aws-cloudformation/cloudformation-coverage-roadmap/issues/112

マネジメントコンソールや CLI から直接ボリュームサイズを変更した場合には EC2 の再作成は発生しないため、手動で当該操作を実施するというのが対応策です。
しかしながら、手動変更を行ってしまうとテンプレートの内容と実リソースの設定に乖離が発生し、ドリフトが検出されるようになってしまうため、CloudFormation でのリソース管理を継続したい場合は、以下の 3 ステップを踏む必要があります。

  1. 当該の EC2 インスタンスを一時的に CloudFormation スタックの管理下から外す
  2. 手動で EBS のサイズを変更
  3. 当該の EC2 インスタンスを再度 CloudFormation スタックにインポートする

やってみた

以下の CloudFormation テンプレートを利用し、実際に上記の 1~3 の手順を実施してみたいと思います。

AWSTemplateFormatVersion: '2010-09-09'
Description: 'Create EC2'

#----------------------------------------------
# Parameters Section
#----------------------------------------------
Parameters:
  InstanceType:
    Description: EC2 instance type
    Type: String
    Default: t3.micro

  InstanceAMI:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-minimal-kernel-default-x86_64

  RootVolumeSize:
    Description: Size of root volume in GB
    Type: Number
    Default: 16

#----------------------------------------------
# Resources Section
#----------------------------------------------
Resources:
  # VPC
  Vpc:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: Vpc

  # Internet Gateway
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: InternetGateway

  VpcGatewayAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref Vpc
      InternetGatewayId: !Ref InternetGateway

  # Public Subnet
  PublicSubnet01:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref Vpc
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: PublicSubnet01

  # Route Table
  RouteTable01:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref Vpc
      Tags:
        - Key: Name
          Value: RouteTable01

  Route01:
    Type: AWS::EC2::Route
    DependsOn: VpcGatewayAttachment
    Properties:
      RouteTableId: !Ref RouteTable01
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  RouteTableAssociation01:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet01
      RouteTableId: !Ref RouteTable01

  # Security Group
  SecurityGroup01:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow SSH access
      VpcId: !Ref Vpc

  # EC2 Instance
  Instance01:
    Type: AWS::EC2::Instance
    DeletionPolicy: Retain
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: !Ref InstanceAMI
      SubnetId: !Ref PublicSubnet01
      SecurityGroupIds:
        - !Ref SecurityGroup01
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeSize: !Ref RootVolumeSize
            VolumeType: gp3
            DeleteOnTermination: true
      Tags:
        - Key: Name
          Value: Instance01

#----------------------------------------------
# Outputs Section
#----------------------------------------------

EC2 インスタンスを一時的に CloudFormation スタックの管理下から外す

上記のテンプレートを実行し、スタックの作成が完了したところから作業をはじめていきます。
まず、リソースを CloudFormation スタックの管理から外すために、BlockDeviceMappings プロパティを利用している当該の EC2 (Instance01) に関する記載をコメントアウトしたテンプレートファイルを別に用意します。

  # Instance01:
  #   Type: AWS::EC2::Instance
  #   DeletionPolicy: Retain
  #   Properties:
  #     InstanceType: !Ref InstanceType
  #     ImageId: !Ref InstanceAMI
  #     SubnetId: !Ref PublicSubnet01
  #     SecurityGroupIds:
  #       - !Ref SecurityGroup01
  #     BlockDeviceMappings:
  #       - DeviceName: /dev/xvda
  #         Ebs:
  #           VolumeSize: !Ref RootVolumeSize
  #           VolumeType: gp3
  #           DeleteOnTermination: true
  #     Tags:
  #       - Key: Name
  #         Value: Instance01

CloudFormation コンソールで当該スタックを選択し、「更新」をクリックします。
スクリーンショット 2024-11-25 153051

「既存のテンプレートを置換」を選択し、コメントアウト後のテンプレートファイルをアップロードします。
スクリーンショット 2024-11-25 153147

実行前に変更セットを参照し、更新時に当該の EC2 リソースが削除されてしまわないよう、ポリシーアクションが "Retain" になっていることを確認したらテンプレートを実行します。
スクリーンショット 2024-11-25 154451_masked

更新が完了し、EC2 がスタックの管理化から外れたことが確認できました。
スクリーンショット 2024-11-25 154840

手動で EBS のサイズを変更

次に、手動で EBS のサイズを変更します。
マネジメントコンソールで当該の EBS を選択し、ボリュームの変更を選択します。
スクリーンショット 2024-11-25 155105

今回は変更さえすれば拡張後のサイズは何でも良いので、サイズの値を適当に 16 に変更します。
その後、「変更」をクリックし、確認画面で改めて「変更」を選択すれば変更完了です。
スクリーンショット 2024-11-25 155232
スクリーンショット 2024-11-25 155318

なお、当記事の主旨からは外れるため詳細は割愛しますが、EBS ボリュームのサイズ変更後は OS 上でもファイルシステムの拡張作業を実施する必要があるのでご注意ください。[1]

EC2 インスタンスを再度 CloudFormation スタックにインポート

EBS のサイズ変更が完了したので、EC2 を再び CloudFormation スタックにインポートしていきたいと思います。[2]
RootVolumeSize を手動変更後の値である 16 に指定し、EC2 リソースのコメントアウトを解除したテンプレートファイルを改めて事前に用意しておきます。

RootVolumeSize:
  Description: Size of root volume in GB
  Type: Number
  Default: 16

  <中略>

Instance01:
  Type: AWS::EC2::Instance
  DeletionPolicy: Retain
  Properties:
    InstanceType: !Ref InstanceType
    ImageId: !Ref InstanceAMI
    SubnetId: !Ref PublicSubnet01
    SecurityGroupIds:
      - !Ref SecurityGroup01
    BlockDeviceMappings:
      - DeviceName: /dev/xvda
        Ebs:
          VolumeSize: !Ref RootVolumeSize
          VolumeType: gp3
          DeleteOnTermination: true
    Tags:
      - Key: Name
        Value: Instance01

CloudFormation コンソールで当該スタックを選択し、「スタックの更新」→「既存のリソースを使用(リソースをインポート)」をクリックします。
スクリーンショット 2024-11-25 162132

記載の前提条件を確認したら「次へ」をクリックします。
スクリーンショット 2024-11-25 163224

変更後のテンプレートをアップロードします。
スクリーンショット 2024-11-25 163239

「インポートするリソース」の画面が表示されたら、当該 EC2 の InstanceId を入力します。
スクリーンショット 2024-11-25 163415

RootVolumeSize が 16 になっていることを確認します。
スクリーンショット 2024-11-25 163737

更新内容を確認したら「リソースをインポート」を実行します。
スクリーンショット 2024-11-25 163840

実行後、ステータスが "IMPORT_COMPLETE" になり、当該 EC2 が再び CloudFormation スタックの管理化に置かれたことが確認できました。
以上で CloudFormation スタックへのインポートは完了になります。
スクリーンショット 2024-11-25 163928_masked
スクリーンショット 2024-11-25 163936

終わりに

CloudFormation での管理を継続しながら、BlockDeviceMappings プロパティを利用した EBS のサイズ拡張を行うための方法を紹介しました。
手順自体は複雑ではないですが、リソースのインポート作業などの一手間を挟む必要がありますので、同作業を予定する際は事前に検証環境などで流れを確認した上で、実施を検討いただければと思います。

脚注
  1. Amazon EBS ボリュームのサイズ変更後にファイルシステムを拡張 ↩︎

  2. スタックへの既存リソースのインポート ↩︎

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.